home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
FishMarket 1.0
/
FishMarket v1.0.iso
/
fishies
/
476-500
/
disk_497
/
nlcalc
/
source
/
cloader.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-05-06
|
14KB
|
481 lines
/*
* CALC.C Provides a calculator that opens on the active screen when
* you press a specific key sequence. Otherwise, the program
* waits quitely in the background.
*
* Copyright 1989 by Davide P. Cervone.
* You may use this code, provided this copyright notice is kept intact.
*/
#include "cLoader.h"
extern struct IntuitionBase *IntuitionBase;
extern struct GfxBase *GfxBase;
static char *program = PROGRAM;
static char *copyright = COPYRIGHT;
static char *handler = HANDLERCODE; /* The name of the handler file */
#define HANDLER &(handler[2]) /* Handler without the L: */
static struct HandlerData *cHandlerData; /* data shared with handler */
static long Segment; /* The loaded handler segment */
static struct Process *HandlerTask; /* The process created */
static struct MsgPort *InputPort; /* To talk to Input.Device */
static struct IOStdReq *InputBlock; /* IO block for Input.Device */
static int InputDevice; /* Is Input.Device open? */
static int VectorsSet; /* TRUE after SetFunction */
static int ProcStarted; /* TRUE acter CreateProc */
static UWORD KeyCode = 0x50; /* the keycode to activate Calc */
static UWORD Qualifiers = 0; /* and required qualifiers */
struct KeywordDef /* keywords and ther qualifiers */
{
char *Name;
UWORD Qualifier;
};
static struct KeywordDef Keyword[] =
{
{"LSHIFT", IEQUALIFIER_LSHIFT},
{"RSHIFT", IEQUALIFIER_RSHIFT},
{"SHIFT", IEQUALIFIER_LSHIFT},
{"CAPSLOCK", IEQUALIFIER_CAPSLOCK},
{"CONTROL", IEQUALIFIER_CONTROL},
{"LALT", IEQUALIFIER_LALT},
{"RALT", IEQUALIFIER_RALT},
{"ALT", IEQUALIFIER_LALT},
{"LAMIGA", IEQUALIFIER_LCOMMAND},
{"RAMIGA", IEQUALIFIER_RCOMMAND},
{"AMIGA", IEQUALIFIER_LCOMMAND},
{"LCOMMAND", IEQUALIFIER_LCOMMAND},
{"RCOMMAND", IEQUALIFIER_RCOMMAND},
{NULL}
};
/*
* DoExit()
*
* General purpose error-exit routine. Print an error message if one was
* supplied (it can have up to three parameters), and then clean up any
* memory, libraries, etc. that need to be handled before exiting.
*/
static void DoExit(s,x1,x2,x3)
char *s, *x1, *x2, *x3;
{
long status = EXIT_OK;
ULONG signals;
if (s != NULL)
{
printf(s,x1,x2,x3);
printf("\n");
status = EXIT_ERROR;
}
if (VectorsSet) UnSetVectors();
if (InputDevice) CloseDevice(InputBlock);
if (InputBlock) DeleteStdIO(InputBlock);
if (InputPort) DeletePort(InputPort);
if (ProcStarted)
{
Signal(HandlerTask,ENDSIGNAL);
signals = Wait(ENDSIGNAL | SIGBREAKF_CTRL_C);
if (signals & SIGBREAKF_CTRL_C) printf("CTRL-C detected!!!\n");
}
if (Segment) UnLoadSeg(Segment);
if (IntuitionBase) CloseLibrary(IntuitionBase);
if (GfxBase) CloseLibrary(GfxBase);
exit(status);
}
/*
* CheckLibOpen()
*
* Call OpenLibrary() for the specified library, and check that the
* open succeeded.
*/
static void CheckLibOpen(lib,name,rev)
APTR *lib;
char *name;
int rev;
{
extern APTR OpenLibrary();
if ((*lib = OpenLibrary(name,(LONG)rev)) == NULL)
DoExit("Can't open %s",name);
}
/*
* CheckArguments()
*
* For each command-line argument:
* Look through the keyword list for the named argument.
* If no match found, then
* Check to see if the argument is an F-key name ('F1','F2', etc).
* If so, then set the KeyCode accordingly,
* Otherwise, try to read a keycode number.
* If unsuccessful, then error.
* Otherwise (a keyword was found)
* so add the requested qualifier to the required qualifier list.
*/
static void CheckArguments(argc,argv)
int argc;
char **argv;
{
short i;
int NotFound;
long Code;
while (--argc)
{
argv++;
for (i=0, NotFound=TRUE; Keyword[i].Name && NotFound; i++)
NotFound = stricmp(*argv,Keyword[i].Name);
if (NotFound)
{
if (((*argv)[0] == 'F' || (*argv)[0] == 'f') &&
(((*argv)[1] >= '1' && (*argv)[1] <= '9' && (*argv)[2] == 0) ||
((*argv)[1] == '1' && (*argv)[2] == '0' && (*argv)[3] == 0)))
{
if ((*argv)[2] == 0)
KeyCode = 0x50 + (*argv)[1] - '1';
else
KeyCode = 0x59;
} else {
if (sscanf(*argv,"%x",&Code) != 1)
DoExit("Unrecognized keyword '%s'",*argv);
KeyCode = Code;
}
} else {
Qualifiers ^= Keyword[i-1].Qualifier;
}
}
}
/*
* LoadHandler()
*
* Try to LoadSeg the handler from the current directory, and if it is not
* found, try the L: directory. If neither can be loaded, exit with an
* error message. Once the handler is loaded, create a process from the
* loaded segment (error if it could not be created) and set a flag so
* that we can clean up if other errors occur.
*/
static void LoadHandler()
{
struct Process *theProcess;
if ((Segment = LoadSeg(HANDLER)) == NULL)
if ((Segment = LoadSeg(handler)) == NULL)
DoExit("Can't load %s",handler);
theProcess = CreateProc(HANDLERTASKNAME,0L,Segment,2048L);
if (theProcess == NULL) DoExit("Can't Create Handler Process");
ProcStarted = TRUE;
}
/*
* SetupHandler()
*
* Look for the handler task, and error if it can't be found. Get a message
* port and a new StartupMessage structure to send the the Handler. Put
* the loader version number in the StartupMessage so the Handler can check
* whether it is OK (if not, it will return a NULL HandlerData pointer).
* Send the message to the Handler, and wait for a reply. When it is
* returned, get the HandlerData pointer, and free what we allocated.
* If the HandlerData is NULL, then there was a version mismatch reported
* by the Handler, otherwise, check the handler version to make sure we know
* how to set it up. Finally, set thePort the the Handler Port value.
*/
static void SetupHandler(thePort)
struct MsgPort **thePort;
{
struct StartupMessage *sMessage;
struct MsgPort *rPort;
ULONG signals;
ULONG rSig;
HandlerTask = FindTask(HANDLERTASKNAME);
if (HandlerTask == NULL) DoExit("Can't Find Handler Task");
NEWPORT(rPort);
if (NEWSTARTUP(sMessage))
{
rSig = ONE << rPort->mp_SigBit;
sMessage->sm_Message.mn_ReplyPort = rPort;
sMessage->sm_HandlerData = NULL;
sMessage->sm_ParentTask = (struct Task *)FindTask(NULL);
sMessage->sm_LoadVers = LOADVERS;
PutMsg(&(HandlerTask->pr_MsgPort),sMessage);
signals = Wait(rSig | SIGBREAKF_CTRL_C);
if (signals & SIGBREAKF_CTRL_C) DoExit("CTRL-C Detected!");
GETSTARTUP(rPort); cHandlerData = sMessage->sm_HandlerData;
FREESTARTUP(sMessage);
DeletePort(rPort);
if (cHandlerData == NULL) DoExit("%s reports a version mismatch",HANDLER);
if (var(MajVers) < MINHMAJVERS ||
(var(MajVers) == MINHMAJVERS && var(MinVers) < MINHMINVERS))
DoExit("Version mismatch with %s",HANDLER);
*thePort = &(cHandlerData->HandlerPort);
} else {
DeletePort(rPort);
DoExit("Can't Get Memory for Startup Message");
}
}
/*
* StartHandler()
*
* Send the Handler the start signal so that it know everything is
* set up for it. Clear the old ParentTask pointer, since the task
* that eventually removes the process may not be the same as the one
* that started it.
*/
void StartHandler()
{
Signal(HandlerTask,STARTSIGNAL);
Forbid();
VAR(ParentTask) = NULL;
Permit();
}
/*
* StopHandler()
*
* Send the Handler the stop signal, and wait for a reply (the Handler
* may need to clean things up before we remove it). Be sure that the
* ParentTask points to us, and not to the original loader task, which
* may not be the same.
*/
void StopHandler()
{
ULONG signals;
Forbid();
VAR(ParentTask) = (struct Task *)FindTask(NULL);
Permit();
Signal(HandlerTask,ENDSIGNAL);
signals = Wait(ENDSIGNAL | SIGBREAKF_CTRL_C);
if (signals & SIGBREAKF_CTRL_C) DoExit("CTRL-C detected!!");
}
/*
* TellInputDevice()
*
* Create a port and I/O block, then open the input device. Set up the
* I/O block to add or remove the input handler, and send the request
* to the input device. Finally, close the device and delete the
* I/O block and port.
*/
void TellInputDevice(function)
int function;
{
long status;
extern struct MsgPort *CreatePort();
extern struct IOStdReq *CreateStdIO();
if ((InputPort = CreatePort(0,0)) == NULL) DoExit("Can't Create Port");
if ((InputBlock = CreateStdIO(InputPort)) == NULL)
DoExit("Can't Create Standard IO Block");
InputDevice = (OpenDevice("input.device",0,InputBlock,0) == 0);
if (InputDevice == FALSE) DoExit("Can't Open 'input.device'");
InputBlock->io_Command = (long) function;
InputBlock->io_Data = (APTR) var(Handler_Interrupt);
if (status = DoIO(InputBlock)) DoExit("Error from DoIO: %ld",status);
CloseDevice(InputBlock); InputDevice = FALSE;
DeleteStdIO(InputBlock); InputBlock = NULL;
DeletePort(InputPort); InputPort = NULL;
}
/*
* SetVectors()
*
* Set the Intuition library vectors for the routines specified by the
* handler. Save the old routine pointers for later replacement.
*/
void SetVectors()
{
if (var(aCloseScreen) && var(OldCloseScreen))
{
VAR(OldCloseScreen) =
SetFunction(IntuitionBase,&LVOCloseScreen,var(aCloseScreen));
VectorsSet = TRUE;
}
}
/*
* UnSetVectors()
*
* Replace the old Intuition library vectors, but make sure that no one
* else has changed them behind our back. If they are not the same as
* what we set them to originally, then put back the ones that we found,
* and return an error status.
*/
int UnSetVectors()
{
long NewCloseScreen;
int status = TRUE;
if (var(aCloseScreen) && var(OldCloseScreen))
{
Forbid();
NewCloseScreen =
SetFunction(IntuitionBase,&LVOCloseScreen,VAR(OldCloseScreen));
if (NewCloseScreen != (long) var(aCloseScreen))
{
SetFunction(IntuitionBase,&LVOCloseScreen,NewCloseScreen);
status = FALSE;
}
Permit();
}
return(status);
}
/*
* SetVariables()
*
* The HandlerData structure is used to allow the loading program to
* set up variables needed by the handler (like Intuitionbase, etc.). This
* keeps the handler code to a minimum. The loader retains pointers to the
* linked lists, in case it needs to free memory on behalf of the handler.
*/
void SetVariables(thePort)
struct MsgPort *thePort;
{
VAR(IntuitionBase) = IntuitionBase;
VAR(GfxBase) = GfxBase;
var(Segment) = Segment;
VAR(KeyCode) = KeyCode;
VAR(Qualifiers) = Qualifiers;
}
/*
* GetVariables()
*
* Look up the values stored in the HandlerData structure. The
* Intuition library already was opened, and we will need to close it.
* Similarly for the Graphics library.
*/
void GetVariables(thePort)
struct MsgPort *thePort;
{
cHandlerData = (struct HandlerData *)thePort;
IntuitionBase = VAR(IntuitionBase);
GfxBase = VAR(GfxBase);
}
/*
* Main()
*
* Look for the Handler Process.
* If the process does not exist, then the Handler is not active, so:
* Handle the arguments (if any).
* Open libraries.
* Load the handler code and create the process.
* Send the startup message to the process and get the HandlerData.
* Set the variables needed by the handler.
* Set the library vectors for the handler routines.
* Add the input handler into the Input Device chain.
* Add the port (supplied by the handler) into the system list so we
* can find it later.
* Signal the process that all is OK.
* Notify the user that all is ready.
* else (the process already exists, so the Handler already is active)
* Get the pointer to the HandlerData structure from the port,
* and get any variables we need from the structure.
* Check that the loader versions are compatible.
* Remove the input handler from the Input Device chain
* Signal the Handler to stop, and wait for reply.
* Try to remove the SetFunction calls.
* If successfull, then
* Remove the port from the system list.
* Signal Handler to end and wait for reply.
* Unload the handler segment list.
* Notify the user that the Handler is deactivated.
* Close libraries.
* else (we could not replace the functions)
* Put back the input handler.
* Signal the Handler to continue.
* Inform the user that the Handler can not be removed.
*/
void main(argc,argv)
int argc;
char **argv;
{
struct MsgPort *NamedPort;
HandlerTask = FindTask(HANDLERTASKNAME);
if (HandlerTask == NULL)
{
if (argc > 1) CheckArguments(argc,argv);
CheckLibOpen(&IntuitionBase,"intuition.library",INTUITION_REV);
CheckLibOpen(&GfxBase,"graphics.library",GRAPHICS_REV);
LoadHandler();
SetupHandler(&NamedPort);
SetVariables(NamedPort);
SetVectors(NamedPort);
TellInputDevice(IND_ADDHANDLER);
AddPort(NamedPort);
StartHandler();
printf("%s v%d.%d.%d Installed\n",program,
var(MajVers),var(MinVers),LOADVERS);
} else {
NamedPort = FindPort(PORTNAME);
if (NamedPort == NULL) DoExit("Can't find port '%s'",PORTNAME);
GetVariables(NamedPort);
if (var(MinLoadVers) > LOADVERS || var(MajVers) < MINHMAJVERS ||
(var(MajVers) == MINHMAJVERS && var(MinVers) < MINHMINVERS))
{
printf("Loader version mismatch\n");
printf("%s not removed\n",program);
} else {
TellInputDevice(IND_REMHANDLER);
StopHandler();
if (UnSetVectors(NamedPort))
{
RemPort(NamedPort);
StopHandler();
UnLoadSeg(var(Segment));
printf("%s removed\n",program);
CloseLibrary(IntuitionBase);
CloseLibrary(GfxBase);
} else {
TellInputDevice(IND_ADDHANDLER);
StartHandler();
printf("SetFunction vectors have been changed!\n");
printf("Cannot remove %s\n",program);
}
}
}
}